package org.jordens.jdbcspy.ui;

import org.jdesktop.swingx.*;
import org.jordens.jdbcspy.jmx.*;
import org.jordens.jdbcspy.sync.*;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * A table panel that displays information about recently executed queries.
 * 
 * @author Adam Jordens
 */
public class QueriesTablePanel extends JPanel
{
    private final QueriesTableModel tableModel = new QueriesTableModel();

    /**
     * @param dataStreamer DataStreamer that will provide updates for this panel.
     */
    public QueriesTablePanel(DataStreamer dataStreamer)
    {
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));

        JXTable table = new JXTable(tableModel);
        table.setSortable(true);

        JScrollPane container = new JScrollPane(table);
        add(container);
        
        dataStreamer.register(new QueriesTablePanelUpdater());
    }

    /**
     * Table model for displaying SQL query information
     */
    private class QueriesTableModel extends AbstractTableModel
    {
        private static final int QUERY = 0;
        private static final int NUMBER_OF_EXECUTIONS = 1;
        private static final int SQL_EXECUTION_TIME = 2;
        private static final int FIRST_EXECUTION = 3;
        private static final int LAST_EXECUTION = 4;

        private List<QueryStatistic> data = new ArrayList<QueryStatistic>();
        private List<String> columns =
                Arrays.asList(
                        "Query",
                        "Number of Executions",
                        "SQL Execution Time",
                        "First Execution",
                        "Last Execution");

        /**
         * {@inheritDoc}
         */
        @Override
        public String getColumnName(int column)
        {
            if (columns.size() > column)
            {
                return columns.get(column);
            }

            return null;
        }

        /**
         * {@inheritDoc}
         */
        public int getRowCount()
        {
            return data.size();
        }

        /**
         * {@inheritDoc}
         */
        public int getColumnCount()
        {
            return columns.size();
        }

        /**
         * {@inheritDoc}
         */
        public Object getValueAt(int row, int column)
        {
            QueryStatistic statistic = data.get(row);
            switch(column)
            {
                case QUERY:
                    return statistic.getSql();
                case NUMBER_OF_EXECUTIONS:
                    return statistic.getCount();
                case FIRST_EXECUTION:
                    return new Date(statistic.getFirstExecution());
                case LAST_EXECUTION:
                    return new Date(statistic.getLastExecution());
                case SQL_EXECUTION_TIME:
                    return statistic.getSQLExecutionTime();
            }

            return null;  
        }

        /**
         * Update any stale QueryStatistics from the current data model w/ their
         * updated values in 'updatedQueryStatistics'.
         *
         * @param updatedQueryStatistics Updated QueryStatistics (sql -> QueryStatistic)
         */
        public void updateData(Map<String, QueryStatistic> updatedQueryStatistics)
        {
            for (int i=0; i<data.size(); i++)
            {
                QueryStatistic queryStatistic = data.get(i);

                QueryStatistic updatedQueryStatistic =
                        updatedQueryStatistics.get(queryStatistic.getSql());

                if (updatedQueryStatistic != null)
                {
                    data.remove(i);
                    data.add(i, updatedQueryStatistic);
                    updatedQueryStatistics.remove(updatedQueryStatistic.getSql());
                }
            }
            data.addAll(updatedQueryStatistics.values());
        }
    }

    /**
     * DataUpdater that will periodically update the table in response to updates
     * from the DataStreamer.
     */
    private class QueriesTablePanelUpdater implements DataUpdater
    {
        /**
         * {@inheritDoc}
         */
        public void update(List<JDBCSpyRecord> jdbcSpyRecords)
        {
            Map<String, QueryStatistic> updatedQueryStatistics =
                    new HashMap<String, QueryStatistic>();
            for (JDBCSpyRecord jdbcSpyRecord : jdbcSpyRecords)
            {
                for (QueryStatistic queryStatistic : jdbcSpyRecord.getQueryStatistics())
                {
                    updatedQueryStatistics.put(queryStatistic.getSql(), queryStatistic);
                }
            }

            QueriesTablePanel.this.tableModel.updateData(updatedQueryStatistics);
            QueriesTablePanel.this.revalidate();
            QueriesTablePanel.this.repaint();
        }

        /**
         * {@inheritDoc}
         */
        public void reset()
        {
            // do nothing
        }
    }
}
